package oa.hleast.xswl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.PhoneUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import oa.hleast.common.redis.component.template.RedisRepository;
import oa.hleast.common.utils.JsonUtil;
import oa.hleast.common.web.exception.BizException;
import oa.hleast.common.web.util.RequestUtils;
import oa.hleast.xswl.common.enums.PointOperatingEnum;
import oa.hleast.xswl.mapper.UmsUserMapper;
import oa.hleast.xswl.pojo.domain.SysDict;
import oa.hleast.xswl.pojo.domain.UmsMember;
import oa.hleast.xswl.pojo.dto.*;
import oa.hleast.xswl.pojo.vo.oms.CartVO;
import oa.hleast.xswl.service.IUmsUserService;
import oa.hleast.xswl.service.SmsSendService;
import oa.hleast.xswl.service.oms.ICartService;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Slf4j
@Service
@Transactional
@AllArgsConstructor
public class UmsUserServiceImpl extends ServiceImpl<UmsUserMapper, UmsMember> implements IUmsUserService {

    private final RedisRepository redisRepository;
    private final SmsSendService smsSendService;
    private final ICartService cartService;


    @Override
    public IPage<UmsMember> list(Page<UmsMember> page, UmsMember spu) {
        List<UmsMember> list = this.baseMapper.list(page, spu);
        page.setRecords(list);
        return page;
    }

    @Override
    public List<SysDict> getGenderDict() {
        return baseMapper.getGenderDict();
    }

    @Override
    public ManagerUserDTO getBaseMember(Long userId) {
        UmsMember user = this.getById(userId);
        if (ObjectUtils.isEmpty(user)) {
            return null;
        }

        ManagerUserDTO dto = new ManagerUserDTO();
        BeanUtil.copyProperties(user, dto);
        return dto;
    }

    @Override
    public MemberDataDTO getMemberByToken(Long userId) {
        UmsMember user = this.getById(userId);
        if (ObjectUtils.isEmpty(user)) {
            return null;
        }

        MemberDataDTO dto = new MemberDataDTO();
        BeanUtil.copyProperties(user, dto);

        // 添加购物车数量
        CartVO cartVO = cartService.getCart(userId);
        if (ObjectUtils.isNotEmpty(cartVO)) {

            log.info("cart cartVO = {}", cartVO);
            int size = cartVO.getItems().size();
            log.info("cart size = {}", size);
            dto.setCartCount((long) size);
        } else {
            dto.setCartCount(0L);
        }

        return dto;
    }

    @Override
    public AuthMemberDTO getUserByOpenid(String openid) {
        UmsMember user = this.getOne(new LambdaQueryWrapper<UmsMember>()
                .eq(UmsMember::getOpenid, openid));
        if (user == null) {
            return null;
        }
        AuthMemberDTO authMemberDTO = new AuthMemberDTO();
        BeanUtil.copyProperties(user, authMemberDTO);
        return authMemberDTO;
    }

    @Override
    public AuthMemberDTO getUserByCustUserId(String custUserId) {
        UmsMember user = this.getOne(new LambdaQueryWrapper<UmsMember>()
                .eq(UmsMember::getCustUserId, custUserId));
        if (user == null) {
            return null;
        }
        AuthMemberDTO authMemberDTO = new AuthMemberDTO();
        BeanUtil.copyProperties(user, authMemberDTO);
        return authMemberDTO;
    }

    @Override
    public AuthMemberDTO getUserByZjfwwUserId(String zjfwwUserId) {
        UmsMember user = this.getOne(new LambdaQueryWrapper<UmsMember>()
                .eq(UmsMember::getZjfwUserId, zjfwwUserId));
        if (user == null) {
            return null;
        }
        AuthMemberDTO authMemberDTO = new AuthMemberDTO();
        BeanUtil.copyProperties(user, authMemberDTO);
        return authMemberDTO;
    }

    @Override
    public AuthMemberDTO getUserByIdCardNum(String idCardNum) {
        UmsMember user = this.getOne(new LambdaQueryWrapper<UmsMember>()
                .eq(UmsMember::getIdCardNum, idCardNum));
        if (user == null) {
            return null;
        }
        AuthMemberDTO authMemberDTO = new AuthMemberDTO();
        BeanUtil.copyProperties(user, authMemberDTO);
        return authMemberDTO;
    }


    @Override
    public List<UmsMember> findInterviewer() {
        List<UmsMember> list = this.list(new LambdaQueryWrapper<UmsMember>()
                .select(UmsMember::getId, UmsMember::getUsername, UmsMember::getNickname)
                .eq(UmsMember::getType, 2)
                .orderByDesc(UmsMember::getGmtCreate)
        );
        return list;
    }

    @Override
    public String sendSms(String phone) {
        // 校验手机号
        boolean isPhone = PhoneUtil.isPhone(phone);
        if (!isPhone) {
            throw new BizException("手机格式不正确");
        }

        //生成流水号
        String uuid = UUID.randomUUID().toString();
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < 6; i++) {
            sb.append(random.nextInt(10));
        }
        Map<String, String> map = new HashMap<>(2);
        map.put("code", sb.toString());
        map.put("phone", phone);

        //短信验证码缓存15分钟，
        redisRepository.setExpire(uuid + ":" + phone, sb.toString(), 15 * 60);
        log.info("缓存验证码：{}", map);
        // 发送短信
        Map<Object, Object> param = new HashMap<>();
        param.put("code", sb.toString());
        String templateParam = JsonUtil.obj2String(param);
        SmsRequestDto smsRequestDto = SmsRequestDto.builder().to(phone).templateCode("SMS_219738940").templateParam(templateParam).build();
        smsSendService.sendSms(smsRequestDto);
        return uuid;
    }

    @Override
    public UmsUserDto getUserDtoById(Long userId) {
        UmsMember pojo = this.getById(userId);
        UmsUserDto dto = new UmsUserDto();
        BeanUtil.copyProperties(pojo, dto);
        return dto;
    }

    @Override
    public Long getPoint(Long userId) {
        UmsMember umsUserOld = this.getById(userId);

        return umsUserOld.getPoint();
    }

    @Override
    public Long getBalance(Long id) {
        UmsMember user = this.getById(id);
        log.info("user = {}", user);
        if (user == null) {
            return 0L;
        }

        Long balance = user.getBalance();

        return ObjectUtils.isEmpty(balance) ? 0L : balance;
    }

    /**
     * 扣减账户余额
     * @param userId 用户ID
     * @param balance 支付金额
     * @return 是否成功
     */
    @Override
    public boolean deductBalance(Long userId, Long balance) {
        boolean result = this.update(new LambdaUpdateWrapper<UmsMember>()
                .setSql("balance = balance - " + balance)
                .eq(UmsMember::getId,userId)
                .apply("balance >= {0}", balance)
        );
        return result;
    }

    /**
     * 修改会员积分
     * @param point 积分数量
     * @param code 操作类型
     */
    @Override
    public boolean updatePoint(Long point, Integer code) {
        Long userId = RequestUtils.getUserId();
        PointOperatingEnum anEnum = PointOperatingEnum.getValue(code);
        Long localPoint = point * (anEnum.getPointType() == 1 ? 1 : -1);
        //保存总积分数
        boolean update = this.update(new LambdaUpdateWrapper<UmsMember>()
                .setSql("point = point +" + localPoint)
                .set(UmsMember::getLastSignInDate, new Date())
                .eq(UmsMember::getId, userId));
        UmsMember umsUserNew = this.getById(userId);

        //保存积分记录 todo
//        Long sumPoint = umsUserNew.getPoint();
//        UmsPointLog pointLog = UmsPointLog.builder()
//                .userId(userId)
//                .sumPoint(sumPoint)
//                .operatingType(pointOperatingEnum.name())
//                .pointType(pointOperatingEnum.getPointType())
//                .thisPoint(localPoint)
//                .build();
//        boolean save = pointLogService.save(pointLog);
        return update ;
    }

}
